﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace vJine.Lua.GUI.BLL {
    class AppCmdProxy : ICommand {
        List<AppCmdExec> AppCmds = new List<AppCmdExec>();
        bool _IsExecutable = true;
        public bool IsExecutable {
            get {
                return this._IsExecutable;
            }
            set {
                if (value != this._IsExecutable) {
                    this._IsExecutable = value;
                    if (this.CanExecuteChanged != null) {
                        this.CanExecuteChanged(this, null);
                    }
                }
            }
        }
        public bool CanExecute(object parameter) {
            return this.IsExecutable;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter) {
            throw new NotImplementedException();
        }

        LuaContext luaContext;
        NodeConfig luaConfig;
        Action<NodeConfig> cmd_init;
        Action<NodeConfig> cmd_finish;
        public AppCmdProxy(DependencyObject uCtrl, RichTextBox rtb, LuaContext luaContext, NodeConfig luaConfig, Action<double, double> update_progress, Action<NodeConfig> init, Action<NodeConfig> finish) {
            //
            this.cmd_init = init;
            this.cmd_finish = finish;

            this.luaConfig = luaConfig;
            this.luaContext = luaContext;

            this.set_value_bind(uCtrl, this.luaConfig);
            this.set_command_bind(uCtrl, update_progress);
        }

        AppCmdExec Create(LuaContext context, NodeConfig config, string parameter, Action<double, double> on_progress) {
            config.luaContext = context;
            AppCmdExec cmd = new AppCmdExec(context, config, this, parameter, this.cmd_init, this.cmd_finish, on_progress);
            this.AppCmds.Add(cmd);
            return cmd;
        }

        void set_value_bind(DependencyObject uCtrl, NodeConfig luaConfig) {
            LocalValueEnumerator lve = uCtrl.GetLocalValueEnumerator();
            while (lve.MoveNext()) {
                Binding bind = BindingOperations.GetBinding(uCtrl, lve.Current.Property);
                if (bind != null && bind.Path != null && bind.Path.Path != "(0)") {
                    BindingOperations.ClearBinding(uCtrl, lve.Current.Property);
                    string item_name = bind.Path.Path;
                    NodeConfig nBind = AppCmdExec.get_config(luaConfig, item_name);
                    if (nBind == null) {
                        MessageBox.Show("未找到节点:" + item_name); continue;
                    }
                    Binding bValue = new Binding("value") {
                        Source = nBind, Mode = BindingMode.TwoWay,
                        UpdateSourceTrigger = UpdateSourceTrigger.LostFocus, TargetNullValue = "N/A"
                    };
                    BindingOperations.SetBinding(uCtrl, lve.Current.Property, bValue);
                }
            }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(uCtrl); i++) {
                set_value_bind(VisualTreeHelper.GetChild(uCtrl, i), luaConfig);
            }
        }

        List<NodeConfig> Cmds = new List<NodeConfig>();
        void set_command_bind(DependencyObject uCtrl, Action<double, double> update_progress = null) {
            ICommandSource ics_i = uCtrl as ICommandSource;
            if (ics_i != null) {
                FieldInfo fiDP = uCtrl.GetType().GetField("CommandProperty",
                    BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
                if (fiDP != null) {
                    uCtrl.SetValue((DependencyProperty)fiDP.GetValue(null),
                        this.Create(
                            this.luaContext, this.luaConfig, ics_i.CommandParameter as string, update_progress
                        ));
                }
            }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(uCtrl); i++) {
                this.set_command_bind(VisualTreeHelper.GetChild(uCtrl, i), update_progress);
            }
        }
    }
    class AppCmdExec : ICommand {

        AppCmdProxy cmdProxy;
        LuaContext luaContext;
        NodeConfig luaConfig;
        public AppCmdExec(LuaContext context, NodeConfig nConfig, AppCmdProxy cmdProxy, string parameter, Action<NodeConfig> on_begin, Action<NodeConfig> on_finish, Action<double, double> on_progress) {
            this.cmdProxy = cmdProxy;
            this.luaContext = context;
            this.luaConfig = nConfig;

            cmdProxy.CanExecuteChanged += (object sender, EventArgs e) => {
                if (this.CanExecuteChanged != null) {
                    this.CanExecuteChanged(this, null);
                }
            };

            string command = parameter;
            command = command ?? "";
            command = command.Trim();
            NodeConfig cmdConfig = null;
            string cmd_param = command;
            if (!command.EndsWith("}")) {
                cmdConfig = this.luaConfig;
            } else {
                cmd_param = command.Substring(command.IndexOf('{')).Trim();
                string cmd_name = command.Substring(0, command.IndexOf('{')).Trim();
                cmdConfig = this.get_cmd(this.luaConfig, cmd_name);
                if (cmdConfig == null) {
                    this.executor = () => {
                        MessageBox.Show(string.Format("未找到命令【{0}】，请确认后重试", cmd_name));
                        //this.set_tree_active(this.luaConfig);
                        this.cmdProxy.IsExecutable = true;
                    };
                    return;
                }
            }

            cmdConfig.OnProgress += on_progress;
            this.executor = () => {
                //this.set_tree_active(cmdConfig);
                Action _on_finish = ()=>{
                    cmdConfig.on_finish -= on_finish;
                };
                cmdConfig.on_init += on_begin;
                cmdConfig.on_finish += (NodeConfig cmd) => {
                    try {
                        //this.set_tree_active(this.luaConfig);
                        this.cmdProxy.IsExecutable = true;

                        on_finish(cmd);
                    } finally {
                        cmdConfig.on_init -= on_begin;
                        _on_finish();
                    }
                };
                this.luaContext.eval("_G['--PARAMS--'] = {" + cmd_param + "}");

                cmdConfig.Execute("run");
            };
        }

        public bool CanExecute(object parameter) {
            return this.cmdProxy.IsExecutable;
        }

        public event EventHandler CanExecuteChanged;

        Action executor;
        public void Execute(object parameter) {
            lock (this.cmdProxy) {
                try {
                    this.cmdProxy.IsExecutable = false;

                    this.executor();

                } catch (Exception ex) {
                    MessageBox.Show("ex:" + ex.Message);
                }
            }
        }
        NodeConfig get_cmd(NodeConfig nConfig, string uri, Dictionary<NodeConfig, string> Parents = null) {
            Parents = Parents ?? new Dictionary<NodeConfig, string>();

            if (nConfig == null) {
                return null;
            } else if (Parents.ContainsKey(nConfig)) {
                return null;
            } else if (nConfig.uri == uri) {
                Parents.Clear(); Parents = null; return nConfig;
            } else if (uri.IndexOf('.') < 0 && nConfig.uri.EndsWith("." + uri)) { //同级简写
                Parents.Clear(); Parents = null; return nConfig;
            }

            Parents.Add(nConfig, "");
            foreach (NodeConfig n in nConfig) {
                NodeConfig ni = this.get_cmd(n, uri, Parents);
                if (ni != null) {
                    Parents.Clear(); Parents = null; return ni;
                }
            }

            return this.get_cmd(nConfig.Parent, uri, Parents);
        }

        public static NodeConfig get_config(NodeConfig nConfig, string uri, Dictionary<NodeConfig, string> Parents = null) {
            Parents = Parents ?? new Dictionary<NodeConfig, string>();

            if (nConfig == null) {
                return null;
            } else if (Parents.ContainsKey(nConfig)) {
                return null;
            } else if (nConfig.configs != null) {
                foreach (NodeConfig config_i in nConfig.configs) {
                    if (config_i.uri == uri) {
                        Parents.Clear(); return config_i;
                    } else if (uri.IndexOf('.') < 0 && config_i.uri.EndsWith("." + uri)) { //同级简写
                        Parents.Clear(); return config_i;
                    }
                }
            }

            Parents.Add(nConfig, "");
            foreach (NodeConfig n in nConfig) {
                NodeConfig ni = get_config(n, uri, Parents);
                if (ni != null) {
                    Parents.Clear(); return ni;
                }
            }

            return get_config(nConfig.Parent, uri, Parents);
        }

        void set_tree_active(NodeConfig nConfig) {
            Stack<NodeConfig> leafs = new Stack<NodeConfig>();
            NodeConfig tConfig = nConfig;
            while (tConfig.Parent != null) {
                leafs.Push(tConfig.Parent);
                tConfig = tConfig.Parent;
            }
            if (leafs.Count > 1) {
                leafs.Pop();
                while (leafs.Count > 0) {
                    tConfig = leafs.Pop();
                    tConfig.IsExpanded = true;
                    tConfig.IsActive = true;
                }
            }
            nConfig.IsActive = true;
        }
    }
}
